package com.zyl.pts.utils;

import com.zyl.pts.config.enums.ResultCode;
import com.zyl.pts.config.exception.ServiceException;
import io.jsonwebtoken.*;
import org.springframework.util.StringUtils;

import java.util.Date;
import java.util.Map;

/**
 * @version v1.0
 * @ProjectName: product_source
 * @Package: com.zyl.pts.utils
 * @ClassName: JwtUtil
 * @Description TODO(Jwt工具类)
 * @Author 翟玉龙
 * @Date 2024/11/19-11:09
 */
public class JwtUtil {

    /*
     * 过期时间: 3天
     */
    private static final Long EXPIRE_TIME = 1000L * 60 * 60 * 24 * 3;

    /*
     * 设置密钥
     */
    private static final String SECRET_KEY = "FinalFantasy";

    /*
     * 设置算法
     */
    private static final SignatureAlgorithm SIGNATURE_ALGORITHM =
            SignatureAlgorithm.HS256;

    /**
     * 根据需要传递用户参数
     * @param claims 用户参数载荷
     */
    public static String sign(Map<String, Object> claims) {
        return Jwts.builder()
                // 设置载荷
                .addClaims(claims)
                // 设置过期时间
                .setExpiration(new Date(System.currentTimeMillis() + EXPIRE_TIME))
                // 设置签名
                .signWith(SIGNATURE_ALGORITHM, SECRET_KEY)
                // 生成token
                .compact();
    }

    /**
     * 解析token，获取token中的载荷
     * @param token - token令牌
     * @return 载荷数据
     */
    private static Claims parse(String token) {
        if (!StringUtils.hasText(token)) {
            // token没有值，即未登录
            throw new ServiceException(ResultCode.TOKEN_IS_MISS);
        }
        try {
            // 校验token
            return Jwts.parser()
                    .setSigningKey(SECRET_KEY)
                    .parseClaimsJws(token)
                    .getBody();
        } catch (ExpiredJwtException e) {
            // token失效
            throw new ServiceException(ResultCode.TOKEN_IS_TIMEOUT);
        } catch (MalformedJwtException | SignatureException e) {
            // 出现这两个异常说明token被篡改
            throw new ServiceException(ResultCode.TOKEN_IS_INVALID);
        }
    }

    /**
     * 从token中获取指定属性的值
     * @param token - token令牌
     * @param fieldName - 属性名
     * @param fieldType - 属性类型
     * @return 指定属性的值
     * @param <T> - 返回值类型
     */
    public static <T> T getValue(
            String token,
            String fieldName,
            Class<T> fieldType
    ) {
        Claims claims = parse(token);
        return claims.get(fieldName, fieldType);
    }
}
